/*     */ package com.zimbra.cs.redolog.util;
/*     */ 
/*     */ import com.zimbra.common.localconfig.KnownKey;
/*     */ import com.zimbra.common.localconfig.LC;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.CliUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.db.DbPool;
/*     */ import com.zimbra.cs.redolog.RedoPlayer;
/*     */ import com.zimbra.cs.redolog.RolloverManager;
/*     */ import com.zimbra.cs.redolog.logger.FileHeader;
/*     */ import com.zimbra.cs.redolog.logger.FileLogReader;
/*     */ import com.zimbra.cs.util.Config;
/*     */ import com.zimbra.cs.util.SoapCLI;
/*     */ import com.zimbra.cs.util.Zimbra;
/*     */ import java.io.File;
/*     */ import java.io.FileNotFoundException;
/*     */ import java.io.IOException;
/*     */ import java.io.PrintStream;
/*     */ import java.io.PrintWriter;
/*     */ import java.text.SimpleDateFormat;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Date;
/*     */ import java.util.Enumeration;
/*     */ import java.util.HashMap;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import org.apache.commons.cli.CommandLine;
/*     */ import org.apache.commons.cli.CommandLineParser;
/*     */ import org.apache.commons.cli.GnuParser;
/*     */ import org.apache.commons.cli.HelpFormatter;
/*     */ import org.apache.commons.cli.Option;
/*     */ import org.apache.commons.cli.Options;
/*     */ import org.apache.commons.cli.ParseException;
/*     */ import org.apache.log4j.Appender;
/*     */ import org.apache.log4j.ConsoleAppender;
/*     */ import org.apache.log4j.Logger;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class PlaybackUtil
/*     */ {
/*     */   private static final String OPT_FROM_TIME = "fromTime";
/*     */   private static final String OPT_FROM_SEQ = "fromSeq";
/*     */   private static final String OPT_TO_TIME = "toTime";
/*     */   private static final String OPT_TO_SEQ = "toSeq";
/*     */   private static final String OPT_MAILBOX_ID = "mailboxId";
/*     */   private static final String OPT_LOGFILES = "logfiles";
/*     */   private static final String OPT_STOP_ON_ERROR = "stopOnError";
/*     */   private static final String OPT_THREADS = "threads";
/*     */   private static final String OPT_QUEUE_CAPACITY = "queueCapacity";
/*     */   private static final String OPT_HELP = "h";
/* 123 */   private static Options sOptions = new Options();
/*     */   private Params mParams;
/*     */   
/* 126 */   static { sOptions.addOption(null, "fromTime", true, "Replay from this time (inclusive)");
/* 127 */     sOptions.addOption(null, "fromSeq", true, "Replay from this redolog sequence (inclusive)");
/* 128 */     sOptions.addOption(null, "toTime", true, "Replay to this time (inclusive)");
/* 129 */     sOptions.addOption(null, "toSeq", true, "Replay to this redolog sequence (inclusive)");
/* 130 */     sOptions.addOption(null, "mailboxId", true, "Replay for this mailbox only");
/* 131 */     sOptions.addOption(null, "threads", true, "Number of parallel redo threads; default=50");
/* 132 */     sOptions.addOption(null, "queueCapacity", true, "Queue capacity per player thread; default=100");
/*     */     
/* 134 */     Option logfilesOpt = new Option(null, "logfiles", true, "Replay these logfiles, in order");
/* 135 */     logfilesOpt.setArgs(-2);
/* 136 */     sOptions.addOption(logfilesOpt);
/*     */     
/* 138 */     sOptions.addOption(null, "stopOnError", false, "Stop replay on any error");
/* 139 */     sOptions.addOption("h", "help", false, "Show help (this output)");
/*     */   }
/*     */   
/*     */   private static void usage(String errmsg) {
/* 143 */     if (errmsg != null) {
/* 144 */       System.err.println(errmsg);
/*     */     }
/*     */     
/* 147 */     String usage = "zmplayredo <options>";
/* 148 */     Options opts = sOptions;
/* 149 */     PrintWriter pw = new PrintWriter(System.err, true);
/* 150 */     HelpFormatter formatter = new HelpFormatter();
/* 151 */     formatter.printHelp(pw, formatter.getWidth(), usage, null, opts, formatter.getLeftPadding(), formatter.getDescPadding(), null);
/*     */     
/*     */ 
/* 154 */     pw.flush();
/*     */     
/* 156 */     String trailer = SoapCLI.getAllowedDatetimeFormatsHelp();
/* 157 */     if ((trailer != null) && (trailer.length() > 0)) {
/* 158 */       System.err.println();
/* 159 */       System.err.println(trailer);
/*     */     }
/*     */   }
/*     */   
/*     */   private static CommandLine parseArgs(String[] args) {
/* 164 */     CommandLineParser parser = new GnuParser();
/* 165 */     CommandLine cl = null;
/*     */     try {
/* 167 */       cl = parser.parse(sOptions, args);
/*     */     } catch (ParseException pe) {
/* 169 */       usage(pe.getMessage());
/* 170 */       System.exit(1);
/*     */     }
/* 172 */     return cl;
/*     */   }
/*     */   
/*     */   private static class Params
/*     */   {
/*     */     private static final int MBOX_ID_UNSET = -1;
/*     */     private static final int PLAYER_THREADS = 50;
/*     */     private static final int QUEUE_CAPACITY = 100;
/* 180 */     public long fromTime = Long.MIN_VALUE;
/* 181 */     public long fromSeq = Long.MIN_VALUE;
/* 182 */     public long toTime = Long.MAX_VALUE;
/* 183 */     public long toSeq = Long.MAX_VALUE;
/* 184 */     public int mboxId = -1;
/* 185 */     public int threads = 50;
/* 186 */     public int queueCapacity = 100;
/*     */     public File[] logfiles;
/* 188 */     public boolean stopOnError = false;
/* 189 */     public boolean help = false;
/*     */   }
/*     */   
/*     */   private static Params initParams(CommandLine cl) throws ServiceException, IOException {
/* 193 */     Params params = new Params(null);
/* 194 */     params.help = cl.hasOption("h");
/* 195 */     if (params.help) {
/* 196 */       return params;
/*     */     }
/* 198 */     params.stopOnError = cl.hasOption("stopOnError");
/*     */     
/* 200 */     if (cl.hasOption("fromTime")) {
/* 201 */       String timeStr = cl.getOptionValue("fromTime");
/* 202 */       Date time = SoapCLI.parseDatetime(timeStr);
/* 203 */       if (time != null) {
/* 204 */         params.fromTime = time.getTime();
/* 205 */         SimpleDateFormat f = new SimpleDateFormat(SoapCLI.CANONICAL_DATETIME_FORMAT);
/* 206 */         String tstamp = f.format(time);
/* 207 */         System.out.printf("Using from-time of %s\n", new Object[] { tstamp });
/*     */       } else {
/* 209 */         System.err.printf("Invalid timestamp \"%s\" specified for --%s option\n", new Object[] { timeStr, "fromTime" });
/*     */         
/* 211 */         System.err.println();
/* 212 */         System.err.print(SoapCLI.getAllowedDatetimeFormatsHelp());
/* 213 */         System.exit(1);
/*     */       }
/*     */     }
/* 216 */     if (cl.hasOption("fromSeq")) {
/* 217 */       params.fromSeq = Long.parseLong(cl.getOptionValue("fromSeq"));
/* 218 */       System.out.printf("Using from-sequence of %d\n", new Object[] { Long.valueOf(params.fromSeq) });
/*     */     }
/* 220 */     if (cl.hasOption("toTime")) {
/* 221 */       String timeStr = cl.getOptionValue("toTime");
/* 222 */       Date time = SoapCLI.parseDatetime(timeStr);
/* 223 */       if (time != null) {
/* 224 */         params.toTime = time.getTime();
/* 225 */         SimpleDateFormat f = new SimpleDateFormat(SoapCLI.CANONICAL_DATETIME_FORMAT);
/* 226 */         String tstamp = f.format(time);
/* 227 */         System.out.printf("Using to-time of %s\n", new Object[] { tstamp });
/*     */       } else {
/* 229 */         System.err.printf("Invalid timestamp \"%s\" specified for --%s option\n", new Object[] { timeStr, "toTime" });
/*     */         
/* 231 */         System.err.println();
/* 232 */         System.err.print(SoapCLI.getAllowedDatetimeFormatsHelp());
/* 233 */         System.exit(1);
/*     */       }
/*     */     }
/* 236 */     if (cl.hasOption("toSeq")) {
/* 237 */       params.toSeq = Long.parseLong(cl.getOptionValue("toSeq"));
/* 238 */       System.out.printf("Using to-sequence of %d\n", new Object[] { Long.valueOf(params.toSeq) });
/*     */     }
/* 240 */     if (params.fromSeq > params.toSeq) {
/* 241 */       System.err.println("Error: fromSeq greater than toSeq");
/* 242 */       System.exit(1);
/*     */     }
/* 244 */     if (params.fromTime > params.toTime) {
/* 245 */       System.err.println("Error: fromTime later than toTime");
/* 246 */       System.exit(1);
/*     */     }
/*     */     
/* 249 */     if (cl.hasOption("mailboxId")) {
/* 250 */       params.mboxId = Integer.parseInt(cl.getOptionValue("mailboxId"));
/* 251 */       System.out.printf("Replaying operations for mailbox %d only\n", new Object[] { Integer.valueOf(params.mboxId) });
/*     */     } else {
/* 253 */       System.out.println("Replaying operations for all mailboxes");
/*     */     }
/*     */     
/* 256 */     if (cl.hasOption("threads"))
/* 257 */       params.threads = Integer.parseInt(cl.getOptionValue("threads"));
/* 258 */     System.out.printf("Using %d redo player threads\n", new Object[] { Integer.valueOf(params.threads) });
/* 259 */     if (cl.hasOption("queueCapacity"))
/* 260 */       params.queueCapacity = Integer.parseInt(cl.getOptionValue("queueCapacity"));
/* 261 */     System.out.printf("Using %d as queue capacity for each redo player thread\n", new Object[] { Integer.valueOf(params.queueCapacity) });
/*     */     
/* 263 */     List<File> logList = new ArrayList();
/* 264 */     if (cl.hasOption("logfiles")) {
/* 265 */       String[] fnames = cl.getOptionValues("logfiles");
/* 266 */       params.logfiles = new File[fnames.length];
/* 267 */       for (int i = 0; i < fnames.length; i++) {
/* 268 */         File f = new File(fnames[i]);
/* 269 */         if (f.exists()) {
/* 270 */           logList.add(f);
/*     */         } else {
/* 272 */           throw new FileNotFoundException("No such file: " + f.getAbsolutePath());
/*     */         }
/*     */       }
/*     */     }
/*     */     else {
/* 277 */       Provisioning prov = Provisioning.getInstance();
/* 278 */       Server server = prov.getLocalServer();
/* 279 */       String archiveDirPath = Config.getPathRelativeToZimbraHome(server.getAttr("zimbraRedoLogArchiveDir", "redolog/archive")).getAbsolutePath();
/*     */       
/*     */ 
/* 282 */       String redoLogPath = Config.getPathRelativeToZimbraHome(server.getAttr("zimbraRedoLogLogPath", "redolog/redo.log")).getAbsolutePath();
/*     */       
/*     */ 
/*     */ 
/* 286 */       File archiveDir = new File(archiveDirPath);
/* 287 */       if (archiveDir.exists()) {
/* 288 */         File[] archiveLogs = RolloverManager.getArchiveLogs(archiveDir, params.fromSeq, params.toSeq);
/* 289 */         for (File f : archiveLogs) {
/* 290 */           logList.add(f);
/*     */         }
/*     */       }
/* 293 */       File redoLog = new File(redoLogPath);
/* 294 */       if (redoLog.exists()) {
/* 295 */         FileLogReader logReader = new FileLogReader(redoLog);
/* 296 */         long seq = logReader.getHeader().getSequence();
/* 297 */         if ((params.fromSeq <= seq) && (seq <= params.toSeq)) {
/* 298 */           logList.add(redoLog);
/*     */         }
/*     */       }
/*     */     }
/* 302 */     for (Iterator<File> iter = logList.iterator(); iter.hasNext();) {
/* 303 */       File f = (File)iter.next();
/* 304 */       FileHeader hdr = new FileLogReader(f).getHeader();
/* 305 */       if ((hdr.getFirstOpTstamp() > params.toTime) || ((hdr.getLastOpTstamp() < params.fromTime) && (!hdr.getOpen())))
/*     */       {
/* 307 */         iter.remove();
/* 308 */         System.out.printf("Redolog %s has no operation in the requested time range\n", new Object[] { f.getName() });
/*     */       }
/*     */     }
/* 311 */     params.logfiles = new File[logList.size()];
/* 312 */     params.logfiles = ((File[])logList.toArray(params.logfiles));
/* 313 */     System.out.printf("%d redolog files to play back\n", new Object[] { Integer.valueOf(params.logfiles.length) });
/*     */     
/* 315 */     return params;
/*     */   }
/*     */   
/*     */ 
/*     */   private RedoPlayer mPlayer;
/*     */   
/*     */   public PlaybackUtil(Params params)
/*     */   {
/* 323 */     this.mParams = params;
/* 324 */     if ((this.mParams.mboxId != -1) || (this.mParams.threads == 1)) {
/* 325 */       this.mPlayer = new RedoPlayer(false, true, !this.mParams.stopOnError, false, true);
/*     */     } else {
/* 327 */       this.mPlayer = new ParallelRedoPlayer(false, true, !this.mParams.stopOnError, false, this.mParams.threads, this.mParams.queueCapacity, true);
/*     */     }
/*     */   }
/*     */   
/*     */   public void playback() throws Throwable {
/*     */     try {
/* 333 */       for (File redolog : this.mParams.logfiles) {
/* 334 */         System.out.println("Processing log file: " + redolog.getAbsolutePath());
/* 335 */         long until = this.mParams.toTime;
/* 336 */         if (until < Long.MAX_VALUE)
/* 337 */           until += 1L;
/*     */         try {
/* 339 */           Map<Integer, Integer> mboxIdMap = null;
/* 340 */           if (this.mParams.mboxId != -1) {
/* 341 */             mboxIdMap = new HashMap(1);
/* 342 */             mboxIdMap.put(Integer.valueOf(this.mParams.mboxId), Integer.valueOf(this.mParams.mboxId));
/*     */           }
/* 344 */           this.mPlayer.scanLog(redolog, true, mboxIdMap, this.mParams.fromTime, until);
/*     */         } catch (OutOfMemoryError oome) {
/* 346 */           Zimbra.halt("OutOfMemoryError while replaying redolog: " + oome.getMessage(), oome);
/*     */         } catch (Throwable t) {
/* 348 */           if (this.mParams.stopOnError)
/* 349 */             throw t;
/* 350 */           ZimbraLog.redolog.warn("Ignoring error and moving on: " + t.getMessage(), t);
/*     */         }
/*     */       }
/*     */     } finally {
/* 354 */       this.mPlayer.shutdown();
/*     */     }
/*     */   }
/*     */   
/*     */   public static void main(String[] cmdlineargs)
/*     */     throws Throwable
/*     */   {
/* 361 */     CliUtil.setCliSoapHttpTransportTimeout();
/* 362 */     setup();
/*     */     try {
/* 364 */       CommandLine cl = parseArgs(cmdlineargs);
/* 365 */       Params params = initParams(cl);
/* 366 */       if (params.help) {
/* 367 */         usage(null);
/* 368 */         System.exit(0);
/*     */       }
/*     */       
/* 371 */       PlaybackUtil player = new PlaybackUtil(params);
/* 372 */       player.playback();
/*     */     } finally {
/* 374 */       teardown();
/*     */     }
/*     */   }
/*     */   
/*     */   private static void setup() throws ServiceException
/*     */   {
/* 380 */     ZimbraLog.toolSetupLog4j("INFO", LC.zimbra_log4j_properties.value());
/*     */     
/* 382 */     Logger rootLogger = Logger.getRootLogger();
/* 383 */     Appender consoleAppender = null;
/* 384 */     Enumeration appenders = rootLogger.getAllAppenders();
/* 385 */     while (appenders.hasMoreElements()) {
/* 386 */       Appender appender = (Appender)appenders.nextElement();
/* 387 */       if ((appender instanceof ConsoleAppender)) {
/* 388 */         consoleAppender = appender;
/*     */       }
/*     */     }
/* 391 */     if (consoleAppender != null) {
/* 392 */       rootLogger.removeAppender(consoleAppender);
/*     */     }
/* 394 */     DbPool.startup();
/* 395 */     Zimbra.startupCLI();
/*     */   }
/*     */   
/*     */   private static void teardown()
/*     */     throws ServiceException
/*     */   {}
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/redolog/util/PlaybackUtil.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */